#pragma once

#include <functional>
#include <string>
#include <random>
#include <exception>

#include "config/config_begin.h"
namespace cpp
{
	struct in_place_tag {};

	namespace __utility {
		class __in_place_ {};

		template<class... T>
		class __in_place_type {};

		template<std::size_t I >
		class __in_place_index {};
	}

	using in_place_t = in_place_tag(&)(__utility::__in_place_);

	template <class T>
	using in_place_type_t = in_place_tag(&)(__utility::__in_place_type<T>);

	template <std::size_t N>
	using in_place_index_t = in_place_tag(&)(__utility::__in_place_index<N>);

	constexpr inline in_place_tag in_place(__utility::__in_place_) { return{}; }

	template <class ...T>
	constexpr inline in_place_tag in_place(__utility::__in_place_type<T...>) { return{}; }

	template <std::size_t N>
	constexpr inline in_place_tag in_place(__utility::__in_place_index< N >) { return{}; }

	//////////////////////////////////////////////////////////////////////////

	template< class T, T... >
	struct integer_sequence;

	namespace __utility
	{
		template<class S1, class S2>
		struct __add__helper;
		template<class T, size_t... i, size_t... j>
		struct __add__helper < integer_sequence<T, i...>, integer_sequence<T, j...> >
		{
			using type = integer_sequence < T, i..., j... >;
		};

		template<class S1>
		struct __reverse_helper;

		template<class T>
		struct __reverse_helper < integer_sequence <T> >
		{
			using type = integer_sequence < T>;
		};

		template<class T, T i>
		struct __reverse_helper < integer_sequence <T, i> >
		{
			using type = integer_sequence < T, i >;
		};

		template<class T, T t, T... i>
		struct __reverse_helper < integer_sequence <T, t, i...> >
		{
			using type = typename __add__helper <
				typename __reverse_helper<  integer_sequence <T, i...> >::type,
				integer_sequence <T, t>
			> ::type;
		};
	}

	namespace __utility
	{
		template<class T>
		struct __back_helper;

		template<class T, T t, T... i>
		struct __back_helper < integer_sequence<T, t, i...> >
		{
			static const T value = __back_helper<integer_sequence<T, i...> >::value;
		};

		template<class T, T t>
		struct __back_helper < integer_sequence<T, t> >
		{
			static const T value = t;
		};

		template<class T>
		struct __back_helper < integer_sequence<T> >
		{
		};

		template<class T>
		struct __front_helper;

		template<class T, T t, T... i>
		struct __front_helper < integer_sequence<T, t, i...> >
		{
			static const T value = t;
		};

		template<class T>
		struct __empty_helper;

		template<class T>
		struct __empty_helper< integer_sequence<T> > :std::true_type
		{};

		template<class T, T t, T... i>
		struct __empty_helper < integer_sequence<T, t, i... > > : std::false_type
		{};

		template<class T, size_t index>
		struct __at_helper;

		template<class T, T t, T... i, size_t index>
		struct __at_helper < integer_sequence<T, t, i...>, index >
		{
			using  __next = __at_helper < integer_sequence<T, i...>, index - 1u >;

			static const T value = __next::value;
		};

		template<class T, T t, T... i>
		struct __at_helper < integer_sequence<T, t, i...>, 0 >
		{
			static const T value = t;
		};

		template<class T>
		struct __size_helper;

		template<class T, T t, T... i>
		struct __size_helper < integer_sequence<T, t, i...> >
		{
			using  __next = __size_helper < integer_sequence<T, i...> >;

			static const size_t value = __next::value + 1;
		};

		template<class T, T t>
		struct __size_helper < integer_sequence<T, t> >
		{
			static const size_t value = 1;
		};

		template<class T>
		struct __size_helper < integer_sequence<T> >
		{
			static const size_t value = 0;
		};

	}

	namespace __helper
	{
		template<class Seq>
		struct back
		{
			static const auto value = __utility::__back_helper<Seq>::value;
		};
		template<class Seq>
		struct front
		{
			static const auto value = __utility::__front_helper<Seq>::value;
		};

		template<class Seq>
		struct empty
		{
			static const auto value = __utility::__empty_helper<Seq>::value;
		};

		template<class Seq>
		struct size
		{
			static const size_t value = __utility::__size_helper<Seq>::value;
		};

		template<class Seq, size_t index>
		struct at
		{
			static_assert(index < size<Seq>::value, "index out of range");
			static const auto value = __utility::__at_helper<Seq, index>::value;
		};
	}


	template< class T, T... Ints >
	struct integer_sequence
	#if defined( _MSC_VER) && _MSC_VER>=1900
		: std::integer_sequence<T, Ints...>
	#endif
	{
		typedef T value_type;
		static constexpr size_t size() noexcept { return sizeof...(Ints); }
	};

	template<class Sequence>
	using reverse_integer_range = typename __utility::__reverse_helper< Sequence > ::type;


	template<class Sequence, size_t index>
	constexpr auto integer_range_at = __helper::at<Sequence, index>::value;


	template<std::size_t... Ints>
	using index_sequence = integer_sequence < std::size_t, Ints... >;

	//////////////////////////////////////////////////////////////////////////

	namespace __utility {
		template <class T, T _b, T _e, T... I>
		struct _integer_range_helper
		{
			static_assert(_b < _e, "invalid range");
			using __next = _integer_range_helper < T, _b + 1, _e, I..., _b >;
			using type = typename __next::type;
		};
		template <class T, T _e, T... I>
		struct _integer_range_helper < T, _e, _e, I... >
		{
			using type = integer_sequence < T, I... >;
		};


		template <class T, T _b, T _e>
		struct _integer_range
		{
			using type = typename __add__helper <
				typename _integer_range_helper<T, _b, (_b + _e) / 2 >::type,
				typename _integer_range_helper<T, (_b + _e) / 2, _e>::type
			>::type;
		};

	}

	template<class T, T N>
	using make_integer_sequence = typename __utility::_integer_range_helper<T, 0, N>::type;

	template<std::size_t N>
	using make_index_sequence = typename __utility::_integer_range_helper<size_t, 0, N>::type;

	template<class... T>
	using index_sequence_for = make_index_sequence < sizeof...(T) >;

	template<class T, T _b, T _e>
	using make_integer_range = typename __utility::_integer_range_helper<T, _b, _e>::type;

	template<std::size_t _b, std::size_t _e>
	using make_index_range = typename __utility::_integer_range_helper<size_t, _b, _e>::type;
}



namespace cpp
{
	namespace utility
	{
		template<class T>
		class singleton
		{
			singleton(singleton const&) = delete;
			singleton& operator=(singleton const&) = delete;
		protected:
			singleton()
			{
				assert(!_instance);
				_instance = static_cast<T*>(this);
			}
			~singleton()
			{
				_instance = nullptr;
			}
		public:
			static T* instance()
			{
				assert(_instance);
				return _instance;
			}

		private:
			static T* _instance;
		};

		template<class T>
		T* singleton<T>::_instance = nullptr;


		using std::swap;
		template<class T>
		void swap_adl(T& l, T& r) noexcept(noexcept(swap(l, r)))
		{
			swap(l, r);
		}
	}


	template< typename T >
	inline typename std::add_const< T >::type& as_const(T &t) noexcept { return t; }

	template <class T>
	void as_const(const T&&) = delete;

	template <class T>
	typename std::decay<T>::type decay_copy(T&& v) { return std::forward<T>(v); }

	template< class E, class = std::enable_if_t<std::is_enum< E >::value>  >
	inline std::underlying_type_t< E > underlying_type_v(E e) noexcept
	{
		return static_cast<std::underlying_type_t< E >>(e);
	}
}


namespace cpp
{
	namespace __compressed_pair
	{
		template <class T1, class T2, bool IsSame, bool B1, bool B2>
		struct compressed_pair__;

		template <class T1, class T2>
		struct compressed_pair__<T1, T2, false, false, false>
		{
			T1&			first() { return _first; }
			T1 const&	first() const { return _first; }


			T2&			second() { return _second; }
			T2 const&	second() const { return _second; }

			template<int _ = 1, class = std::enable_if_t < _ == 1 &&
				std::is_default_constructible<T1>::value &&
				std::is_default_constructible<T2>::value
				>>
				constexpr compressed_pair__()
				:_first()
				, _second()
			{

			}

			constexpr compressed_pair__(const T1& x, const T2& y)
				:_first(x)
				, _second(y)
			{

			}


			template<class U1, class U2, class = std::enable_if_t <
				std::is_convertible<U1&&, T1>::value&&
				std::is_convertible<U2&&, T2>::value
				>>
				constexpr compressed_pair__(U1&& u1, U2&& u2)
				: _first(std::forward<U1>(u1))
				, _second(std::forward<U2>(u2))
			{

			}

			template< class U1, class U2, bool IsSame, bool B1, bool B2>
			constexpr compressed_pair__(const compressed_pair__< U1, U2, IsSame, B1, B2 >& p)
				:_first(p.first())
				, _second(p.second())

			{

			}

			template< class U1, class U2, bool IsSame, bool B1, bool B2>
			constexpr compressed_pair__(compressed_pair__< U1, U2, IsSame, B1, B2 > && p)
				:_first(std::forward<U1>(p.first()))
				, _second(std::forward<U2>(p.second()))

			{

			}

			template< class... Args1, class... Args2 >
			compressed_pair__(std::piecewise_construct_t,
							  std::tuple<Args1...> first_args,
							  std::tuple<Args2...> second_args)
				:_first(std::forward<Args1>(first_args)...)
				, _second(std::forward<Args2>(second_args)...)
			{

			}

			constexpr compressed_pair__(const compressed_pair__& p) = default;

			constexpr compressed_pair__(compressed_pair__&& p) = default;


			compressed_pair__& operator=(const compressed_pair__& other) = default;

			compressed_pair__& operator=(compressed_pair__&& other) = default;
		protected:
			template< class U1, class U2>
			void assign(U1&& u1, U2&&u2)
			{
				first() = std::forward<U1>(u1);
				second() = std::forward<U2>(u1);
			}

			void swap(compressed_pair__ & other) noexcept(
				noexcept(cpp::utility::swap_adl(_first, other._first)) &&
				noexcept(cpp::utility::swap_adl(_second, other._second))
				)
			{
				cpp::utility::swap_adl(_first, other._first);
				cpp::utility::swap_adl(_second, other._second);
			}
		private:
			T1 _first;
			T2 _second;
		};

		template <class T1, class T2>
		struct compressed_pair__<T1, T2, false, true, false> : private std::remove_cv_t<T1>
		{

			T1&			first() { return *this; }
			T1 const&	first() const { return *this; }

			T2&			second() { return _second; }
			T2 const&	second() const { return _second; }


			template<int _ = 1, class = std::enable_if_t < _ == 1 &&
				std::is_default_constructible<T1>::value &&
				std::is_default_constructible<T2>::value
				>>
				constexpr compressed_pair__()
				:std::remove_cv_t<T1>()
				, _second()
			{

			}

			constexpr compressed_pair__(const T1& x, const T2& y)
				:std::remove_cv_t<T1>(x)
				, _second(y)
			{

			}


			template<class U1, class U2, class = std::enable_if_t <
				std::is_convertible<U1&&, T1>::value&&
				std::is_convertible<U2&&, T2>::value
				>>
				constexpr compressed_pair__(U1&& u1, U2&& u2)
				: std::remove_cv_t<T1>(std::forward<U1>(u1))
				, _second(std::forward<U2>(u2))
			{

			}

			template< class U1, class U2, bool IsSame, bool B1, bool B2>
			constexpr compressed_pair__(const compressed_pair__< U1, U2, IsSame, B1, B2 >& p)
				:std::remove_cv_t<T1>(p.first())
				, _second(p.second())

			{

			}

			template< class U1, class U2, bool IsSame, bool B1, bool B2>
			constexpr compressed_pair__(compressed_pair__< U1, U2, IsSame, B1, B2 > && p)
				:std::remove_cv_t<T1>(std::forward<U1>(p.first()))
				, _second(std::forward<U2>(p.second()))

			{

			}

			template< class... Args1, class... Args2 >
			compressed_pair__(std::piecewise_construct_t,
							  std::tuple<Args1...> first_args,
							  std::tuple<Args2...> second_args)
				:std::remove_cv_t<T1>(std::forward<Args1>(first_args)...)
				, _second(std::forward<Args2>(second_args)...)
			{

			}

			constexpr compressed_pair__(const compressed_pair__& p) = default;

			constexpr compressed_pair__(compressed_pair__&& p) = default;

			compressed_pair__& operator=(const compressed_pair__& other) = default;

			compressed_pair__& operator=(compressed_pair__&& other) = default;
		protected:
			template< class U1, class U2>
			void assign(U1&& u1, U2&&u2)
			{
				first() = std::forward<U1>(u1);
				second() = std::forward<U2>(u1);
			}

			void swap(compressed_pair__ & other) noexcept(
				noexcept(cpp::utility::swap_adl(first(), other.first())) &&
				noexcept(cpp::utility::swap_adl(_second, other._second))
				)
			{
				cpp::utility::swap_adl(first(), other.first());
				cpp::utility::swap_adl(_second, other._second);
			}
		private:
			T2 _second;
		};

		template <class T1, class T2>
		struct compressed_pair__<T1, T2, false, true, true> : private std::remove_cv_t<T1>, private std::remove_cv_t<T2>
		{
			T1&			first() { return *this; }
			T1 const&	first() const { return *this; }

			T2&			second() { return *this; }
			T2 const&	second() const { return *this; }


			template<int _ = 1, class = std::enable_if_t < _ == 1 &&
				std::is_default_constructible<T1>::value &&
				std::is_default_constructible<T2>::value
				>>
				constexpr compressed_pair__()
				: std::remove_cv_t<T1>()
				, std::remove_cv_t<T2>()
			{

			}

			constexpr compressed_pair__(const T1& x, const T2& y)
				: std::remove_cv_t<T1>(x)
				, std::remove_cv_t<T2>(y)
			{

			}


			template<class U1, class U2, class = std::enable_if_t <
				std::is_convertible<U1&&, T1>::value&&
				std::is_convertible<U2&&, T2>::value
				>>
				constexpr compressed_pair__(U1&& u1, U2&& u2)
				: std::remove_cv_t<T1>(std::forward<U1>(u1))
				, std::remove_cv_t<T2>(std::forward<U2>(u2))
			{

			}

			template< class U1, class U2, bool IsSame, bool B1, bool B2>
			constexpr compressed_pair__(const compressed_pair__< U1, U2, IsSame, B1, B2 >& p)
				: std::remove_cv_t<T1>(p.first())
				, std::remove_cv_t<T2>(p.second())

			{

			}

			template< class U1, class U2, bool IsSame, bool B1, bool B2>
			constexpr compressed_pair__(compressed_pair__< U1, U2, IsSame, B1, B2 > && p)
				: std::remove_cv_t<T1>(std::forward<U1>(p.first()))
				, std::remove_cv_t<T2>(std::forward<U2>(p.second()))

			{

			}

			template< class... Args1, class... Args2 >
			compressed_pair__(std::piecewise_construct_t,
							  std::tuple<Args1...> first_args,
							  std::tuple<Args2...> second_args)
				: std::remove_cv_t<T1>(std::forward<Args1>(first_args)...)
				, std::remove_cv_t<T2>(std::forward<Args2>(second_args)...)
			{

			}

			constexpr compressed_pair__(const compressed_pair__& p) = default;

			constexpr compressed_pair__(compressed_pair__&& p) = default;

			compressed_pair__& operator=(const compressed_pair__& other) = default;

			compressed_pair__& operator=(compressed_pair__&& other) = default;
		protected:
			template< class U1, class U2>
			void assign(U1&& u1, U2&&u2)
			{
				first() = std::forward<U1>(u1);
				second() = std::forward<U2>(u1);
			}

			void swap(compressed_pair__ & other) noexcept(
				noexcept(cpp::utility::swap_adl(first(), other.first())) &&
				noexcept(cpp::utility::swap_adl(second(), other.second()))
				)
			{
				cpp::utility::swap_adl(first(), other.first());
				cpp::utility::swap_adl(second(), other.second());
			}
		};

		template <class T1, class T2>
		struct compressed_pair__<T1, T2, false, false, true> : private std::remove_cv_t<T2>
		{
			T1&			first() { return _first; }
			T1 const&	first() const { return _first; }

			T2&			second() { return *this; }
			T2 const&	second() const { return *this; }

			template<bool _ = true, class = std::enable_if_t <_ &&
				std::is_default_constructible<T1>::value &&
				std::is_default_constructible<T2>::value
				>>
				constexpr compressed_pair__()
				:_first()
				, std::remove_cv_t<T2>()
			{

			}

			constexpr compressed_pair__(const T1& x, const T2& y)
				:_first(x)
				, std::remove_cv_t<T2>(y)
			{

			}


			template<class U1, class U2, class = std::enable_if_t <
				std::is_convertible<U1&&, T1>::value&&
				std::is_convertible<U2&&, T2>::value
				>>
				constexpr compressed_pair__(U1&& u1, U2&& u2)
				: _first(std::forward<U1>(u1))
				, std::remove_cv_t<T2>(std::forward<U2>(u2))
			{

			}

			template< class U1, class U2, bool IsSame, bool B1, bool B2>
			constexpr compressed_pair__(const compressed_pair__< U1, U2, IsSame, B1, B2 >& p)
				:_first(p.first())
				, std::remove_cv_t<T2>(p.second())

			{

			}

			template< class U1, class U2, bool IsSame, bool B1, bool B2>
			constexpr compressed_pair__(compressed_pair__< U1, U2, IsSame, B1, B2 > && p)
				:_first(std::forward<U1>(p.first()))
				, std::remove_cv_t<T2>(std::forward<U2>(p.second()))

			{

			}

			template< class... Args1, class... Args2 >
			compressed_pair__(std::piecewise_construct_t,
							  std::tuple<Args1...> first_args,
							  std::tuple<Args2...> second_args)
				:_first(std::forward<Args1>(first_args)...)
				, std::remove_cv_t<T2>(std::forward<Args2>(second_args)...)
			{

			}

			constexpr compressed_pair__(const compressed_pair__& p) = default;

			constexpr compressed_pair__(compressed_pair__&& p) = default;

			compressed_pair__& operator=(const compressed_pair__& other) = default;

			compressed_pair__& operator=(compressed_pair__&& other) = default;
		protected:
			template< class U1, class U2>
			void assign(U1&& u1, U2&&u2)
			{
				first() = std::forward<U1>(u1);
				second() = std::forward<U2>(u1);
			}

			void swap(compressed_pair__ & other) noexcept(
				noexcept(cpp::utility::swap_adl(first(), other.first())) &&
				noexcept(cpp::utility::swap_adl(second(), other.second()))
				)
			{
				cpp::utility::swap_adl(first(), other.first());
				cpp::utility::swap_adl(second(), other.second());
			}
		private:
			T1 _first;
		};

		template <class T1, class T2>
		struct compressed_pair__<T1, T2, true, false, false>
		{
			T1&			first() { return _first; }
			T1 const&	first() const { return _first; }


			T2&			second() { return _second; }
			T2 const&	second() const { return _second; }

			template<bool _ = true, class = std::enable_if_t <_ &&
				std::is_default_constructible<T1>::value &&
				std::is_default_constructible<T2>::value
				>>
				constexpr compressed_pair__()
				:_first()
				, _second()
			{

			}

			constexpr compressed_pair__(const T1& x, const T2& y)
				:_first(x)
				, _second(y)
			{

			}


			template<class U1, class U2, class = std::enable_if_t <
				std::is_convertible<U1&&, T1>::value&&
				std::is_convertible<U2&&, T2>::value
				>>
				constexpr compressed_pair__(U1&& u1, U2&& u2)
				: _first(std::forward<U1>(u1))
				, _second(std::forward<U2>(u2))
			{

			}

			template< class U1, class U2, bool IsSame, bool B1, bool B2>
			constexpr compressed_pair__(const compressed_pair__< U1, U2, IsSame, B1, B2 >& p)
				:_first(p.first())
				, _second(p.second())

			{

			}

			template< class U1, class U2, bool IsSame, bool B1, bool B2>
			constexpr compressed_pair__(compressed_pair__< U1, U2, IsSame, B1, B2 > && p)
				:_first(std::forward<U1>(p.first()))
				, _second(std::forward<U2>(p.second()))

			{

			}

			template< class... Args1, class... Args2 >
			compressed_pair__(std::piecewise_construct_t,
							  std::tuple<Args1...> first_args,
							  std::tuple<Args2...> second_args)
				:_first(std::forward<Args1>(first_args)...)
				, _second(std::forward<Args2>(second_args)...)
			{

			}

			constexpr compressed_pair__(const compressed_pair__& p) = default;

			constexpr compressed_pair__(compressed_pair__&& p) = default;

			compressed_pair__& operator=(const compressed_pair__& other) = default;

			compressed_pair__& operator=(compressed_pair__&& other) = default;
		protected:
			template< class U1, class U2>
			void assign(U1&& u1, U2&&u2)
			{
				first() = std::forward<U1>(u1);
				second() = std::forward<U2>(u1);
			}
			void swap(compressed_pair__ & other) noexcept(
				noexcept(cpp::utility::swap_adl(first(), other.first())) &&
				noexcept(cpp::utility::swap_adl(second(), other.second()))
				)
			{
				cpp::utility::swap_adl(first(), other.first());
				cpp::utility::swap_adl(second(), other.second());
			}
		private:
			T1 _first;
			T2 _second;
		};

		template <class T1, class T2>
		struct compressed_pair__<T1, T2, true, true, true> : private std::remove_cv_t<T1>
		{
			T1&			first() { return *this; }
			T1 const&	first() const { return *this; }

			T2&			second() { return _second; }
			T2 const&	second() const { return _second; }

			template<bool _ = true, class = std::enable_if_t <_ &&
				std::is_default_constructible<T1>::value &&
				std::is_default_constructible<T2>::value
			> >
				constexpr compressed_pair__()
				: std::remove_cv_t<T1>()
				, _second()
			{

			}

			constexpr compressed_pair__(const T1& x, const T2& y)
				: std::remove_cv_t<T1>(x)
				, _second(y)
			{

			}


			template<class U1, class U2, class = std::enable_if_t <
				std::is_convertible<U1&&, T1>::value&&
				std::is_convertible<U2&&, T2>::value
				>>
				constexpr compressed_pair__(U1&& u1, U2&& u2)
				: std::remove_cv_t<T1>(std::forward<U1>(u1))
				, _second(std::forward<U2>(u2))
			{

			}

			template< class U1, class U2, bool IsSame, bool B1, bool B2>
			constexpr compressed_pair__(const compressed_pair__< U1, U2, IsSame, B1, B2 >& p)
				: std::remove_cv_t<T1>(p.first())
				, _second(p.second())

			{

			}

			template< class U1, class U2, bool IsSame, bool B1, bool B2>
			constexpr compressed_pair__(compressed_pair__< U1, U2, IsSame, B1, B2 > && p)
				: std::remove_cv_t<T1>(std::forward<U1>(p.first()))
				, _second(std::forward<U2>(p.second()))

			{

			}

			template< class... Args1, class... Args2 >
			compressed_pair__(std::piecewise_construct_t,
							  std::tuple<Args1...> first_args,
							  std::tuple<Args2...> second_args)
				: std::remove_cv_t<T1>(std::forward<Args1>(first_args)...)
				, _second(std::forward<Args2>(second_args)...)
			{

			}

			constexpr compressed_pair__(const compressed_pair__& p) = default;

			constexpr compressed_pair__(compressed_pair__&& p) = default;

			compressed_pair__& operator=(const compressed_pair__& other) = default;

			compressed_pair__& operator=(compressed_pair__&& other) = default;
		protected:
			template< class U1, class U2>
			void assign(U1&& u1, U2&&u2)
			{
				first() = std::forward<U1>(u1);
				second() = std::forward<U2>(u1);
			}

			void swap(compressed_pair__ & other) noexcept(
				noexcept(cpp::utility::swap_adl(first(), other.first())) &&
				noexcept(cpp::utility::swap_adl(second(), other.second()))
				)
			{
				cpp::utility::swap_adl(first(), other.first());
				cpp::utility::swap_adl(second(), other.second());
			}
		private:
			T2 _second;
		};
	}

	//////////////////////////////////////////////////////////////////////////
	template <class T1, class T2>
	class compressed_pair :private __compressed_pair::compressed_pair__<T1, T2,
		std::is_same<T1, T2>::value,
		std::is_empty<T1>::value && !std::is_final<T1>::value,
		std::is_empty<T2>::value && !std::is_final<T2>::value>
	{
		using base_t = __compressed_pair::compressed_pair__<T1, T2,
			std::is_same<T1, T2>::value,
			std::is_empty<T1>::value && !std::is_final<T1>::value,
			std::is_empty<T2>::value && !std::is_final<T2>::value>;
	public:

		using	first_type = T1;
		using	second_type = T2;

		constexpr compressed_pair() :base_t() {}

		constexpr compressed_pair(const T1& x, const T2& y) : base_t(x, y) {}


		template<class U1, class U2, class = std::enable_if_t <
			std::is_convertible<U1&&, T1>::value&&
			std::is_convertible<U2&&, T2>::value
			>>
			constexpr compressed_pair(U1&& u1, U2&& u2)
			:base_t(std::forward<U1>(u1), std::forward<U2>(u2))
		{

		}

		template< class U1, class U2 >
		constexpr compressed_pair(const compressed_pair<U1, U2>& p)
			:base_t(p.first(), p.second())
		{

		}

		template< class U1, class U2 >
		constexpr compressed_pair(compressed_pair<U1, U2>&& p)
			:base_t(std::forward<U1>(p.first()), std::forward<U2>(p.second()))
		{

		}

		template< class... Args1, class... Args2 >
		compressed_pair(std::piecewise_construct_t,
						std::tuple<Args1...> first_args,
						std::tuple<Args2...> second_args)
			: base_t(std::piecewise_construct, std::move(first_args), std::move(second_args))
		{

		}

		compressed_pair(const compressed_pair& p) = default;

		compressed_pair(compressed_pair&& p) = default;

		void swap(compressed_pair& other) noexcept(noexcept(base_t::swap(other)))
		{
			base_t::swap(other);
		}


		compressed_pair& operator=(const compressed_pair& other) = default;

		template< class U1, class U2 >
		compressed_pair& operator=(const compressed_pair<U1, U2>& other)
		{
			this->assign(other.first(), other.second());
			return *this;
		}

		compressed_pair& operator=(compressed_pair&& other) = default;

		template< class U1, class U2 >
		compressed_pair& operator=(compressed_pair<U1, U2>&& other)
		{
			this->assign(std::forward<U1>(other.first()), std::forward<U2>(other.second()));
			return *this;
		}

		T1&			first() { return base_t::first(); }
		T1 const&	first() const { return base_t::first(); }

		T2&			second() { return  base_t::second();; }
		T2 const&	second() const { return  base_t::second();; }

	};

	template< class T1, class T2 >
	constexpr bool operator==(const compressed_pair<T1, T2>& lhs, const compressed_pair<T1, T2>& rhs)
	{
		return lhs.first() == rhs.first() && lhs.second() == rhs.second();
	}

	template< class T1, class T2 >
	constexpr bool operator!=(const compressed_pair<T1, T2>& lhs, const compressed_pair<T1, T2>& rhs)
	{
		return lhs.first() != rhs.first() || lhs.second() != rhs.second();
	}

	template< class T1, class T2 >
	constexpr bool operator<(const compressed_pair<T1, T2>& lhs, const compressed_pair<T1, T2>& rhs)
	{
		return lhs.first() < rhs.first() ||
			((rhs.first() < lhs.first()) ? false : lhs.second() < rhs.second());
	}

	template< class T1, class T2 >
	constexpr bool operator<=(const compressed_pair<T1, T2>& lhs, const compressed_pair<T1, T2>& rhs)
	{
		return !(rhs < lhs);
	}

	template< class T1, class T2 >
	constexpr bool operator>(const compressed_pair<T1, T2>& lhs, const compressed_pair<T1, T2>& rhs)
	{
		return rhs < lhs;
	}

	template< class T1, class T2 >
	constexpr bool operator>=(const compressed_pair<T1, T2>& lhs, const compressed_pair<T1, T2>& rhs)
	{
		return !(lhs < rhs);
	}

	template<class T, class U>
	void swap(compressed_pair<T, U>& l, compressed_pair<T, U>& r) noexcept(noexcept(l.swap(r)))
	{
		l.swap(r);
	}

	namespace __compressed_pair
	{
		template<class T>
		struct __decay :std::decay<T> {};

		template<class T>
		struct __decay<std::reference_wrapper<T> > { typedef T& type; };
	}

	template< class T1, class T2,
		class V1 = typename __compressed_pair::__decay< std::decay_t<T1> >::type,
		class V2 = typename __compressed_pair::__decay< std::decay_t<T2> >::type>
		constexpr compressed_pair<V1, V2> make_compressed_pair(T1&& t, T2&& u)
	{
		return{ std::forward<T1>(t),std::forward<T2>(u) };
	}

}

#include "config/config_end.h"